﻿using Microsoft.VisualBasic.FileIO;
using Microsoft.Win32;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Resources;
using System.Threading;
using System.Windows.Forms;

namespace TripleCComiC
{
    /// <summary>
    /// TripleC ComiC Viewer: 
    /// A simply image viewer suit for reading comic.
    /// </summary>
    /// <remarks>
    /// Author:
    /// TripleC feat. benimut
    /// 
    /// Change Log:
    /// 1.7.0.0 2014/08/27
    /// First publish version.
    /// 
    /// 1.7.1.0 2014/08/28
    /// Fix logical error in file name sort and improve.
    /// 1.7.1.1 2014/08/28
    /// Hide debug information.
    /// 
    /// 1.7.2.0 2014/08/29
    /// Enhance checking in show sibling folder.
    /// 1.7.2.1 2014/08/29
    /// Remove show parameter.
    /// 
    /// 1.8.0.0 2014/09/10
    /// Add function for drag image.
    /// 
    /// 1.8.1.0 2014/09/24
    /// Fix logical error in file name sort and improve.
    /// 
    /// 1.8.2.2 2014/09/26
    /// Auto save user setting.
    /// User can set if picture homing when change pictures.
    /// Move picture by number pad.
    /// 1.8.2.3 2014/09/26
    /// Edit help.
    /// 
    /// 1.8.3.0 2014/10/22
    /// Edit moving image by number pad.
    /// 
    /// 1.8.4.0 2014/11/06
    /// Add Anywhere Door feature.
    /// 
    /// 1.8.5.0 2014/11/07
    /// Fix logic error.
    /// Add caching for Anywhere Door.
    /// 1.8.5.1 2014/11/07
    /// Enable show file list.
    /// Show selected image by double click item in file list.
    /// 
    /// 1.8.6.0 2015/01/29
    /// Add setting: "Open in Full Screen".
    /// Auto save size mode such as fit width, fit height and original size.
    /// 1.8.6.1 2015/01/29
    /// Auto save zoom ratio.
    /// 
    /// 1.8.7.0 2015/02/05
    /// Try fix logical error in file name sort and improve.
    /// 
    /// 1.8.7.1 2015/02/06
    /// Try fix logical error in file name sort and improve.
    /// 
    /// 1.8.7.2 2015/02/12
    /// Try fix logical error in file name sort and improve.
    /// 
    /// 1.9.0.0 2015/03/04
    /// Beta version of tumbnail navigation.
    /// 
    /// 1.9.1.0 2015/03/05
    /// Using backgroundworker when load tumbnail in tumbnail navigation.
    /// Fix logical error when load program with argument.
    /// Make item in tumbnail navigation can selected.
    /// 
    /// 1.9.2.0 2015/03/09
    /// Sort file name in tumbnail navigation.
    /// Add sort option: system define.
    /// Save user setting: sort option.
    /// 1.9.2.1 2015/03/09
    /// Add show path in thumbnail navigation.
    /// 
    /// 1.9.2.2 2015/03/10
    /// Add link of my computer in path bar.
    /// 1.9.2.3 2015/03/10
    /// Fix directory name in thumbnail navigation.
    /// Support long file/directory name in thumbnail navigation.
    /// 
    /// 1.9.2.4 2015/03/11
    /// Fix path bar.
    /// 
    /// 1.9.2.5 2015/03/12
    /// Fix double call DoubleClick event in ListItem object.
    /// Fix clash of ListItem._imageCancellation.
    /// Fix error when change file name.
    /// 
    /// 1.9.2.6 2015/03/16
    /// Fix user setting not work when program opened.
    /// Fix sort by system define.
    /// 
    /// 1.9.3.0 2015/03/17
    /// Add key down event: Enter, F2 (change name) of item.
    /// 
    /// 1.9.4.0 2015/03/18
    /// Fix UI was deformed after font changed.
    /// Add delete file function in thumbnail navigation.
    /// 
    /// 1.10.0.1 2015/07/22
    /// Rewrite properties setting interface.
    /// 1.10.0.2 2015/07/22
    /// Can change height of time line bar.
    /// 
    /// SINCE 2014/06/04
    /// </remarks>
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            uiSetting.RatioXChanged += num_RatioX_ValueChanged;
            uiSetting.RatioYChanged += num_RatioY_ValueChanged;
            uiSetting.RatioZoomChanged += num_RatioZoom_ValueChanged;
            uiSetting.BarCheckedChanged += check_Bar_CheckedChanged;
            uiSetting.ButtonFontClick += btn_Font_Click;
            uiSetting.ButtonOKClick += btn_OK_Click;
            uiSetting.Dock = DockStyle.Fill;
            uiSetting.Enabled = false;
            uiSetting.Visible = false;

            String[] args = System.Environment.GetCommandLineArgs();

            try
            {
                ResourceManager rm;
                IDictionaryEnumerator rm_iDic;

                rm = new ResourceManager(
                    "TripleCComiC.lang",
                    Assembly.GetExecutingAssembly());
                rm_iDic = rm.GetResourceSet(
                    System.Threading.Thread.CurrentThread.CurrentCulture,
                    true, true).GetEnumerator();

                // load all string in resource at first time
                while (rm_iDic.MoveNext())
                {
                    LangDict.Add(
                        rm_iDic.Key as string, rm_iDic.Value as string);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }

            if (args.Length > 1)
            {
                int selectedImage = 0;
                string argPath = args[1];

                _currentPath = Path.GetDirectoryName(args[1]);
                _files = SortFileName(GetFiles(_currentPath));
                selectedImage = Array.FindIndex<string>(_files, (file => file == Path.GetFullPath(args[1])));
                ImageNumNow = (selectedImage >= 0) ? selectedImage : 0;
                if (_files.Length == 0)
                {
                    try
                    {
                        string newPath = System.Environment.CommandLine.Replace("\"", "").Substring(System.Environment.GetCommandLineArgs()[0].Length + 1);

                        _currentPath = Path.GetDirectoryName(newPath);
                        _files = SortFileName(GetFiles(_currentPath));
                        selectedImage = Array.FindIndex<string>(_files, (file => file == Path.GetFullPath(newPath)));
                        ImageNumNow = (selectedImage >= 0) ? selectedImage : 0;
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message);
                    }
                }
            }
            SetStyle(ControlStyles.SupportsTransparentBackColor, true);
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            this.ContextMenuStrip = contextMenuStrip1;
            pic_Main.ContextMenuStrip = contextMenuStrip1;

            this.WindowState = FormWindowState.Normal;
            this.FormBorderStyle = FormBorderStyle.Sizable;
            this.TopMost = false;

            if (_files.Length > 0)
            {
                this.Text = _currentPath;
                LoadImage(ImageNumNow);
            }
            SetDistance();
            this.Deactivate += Form1_Deactivate;
            timer_Cache.Start();
            SetBarLocSize();
            LoadSetting();

            _timerPlay.Tick += _timerPlay_Tick;
            _timerReverse.Tick += _timerReverse_Tick;
        }

        private void Form1_Deactivate(object sender, EventArgs e)
        {
            if (this.WindowState == FormWindowState.Maximized)
            {
                this.WindowState = FormWindowState.Minimized;
            }
        }

        private void Form1_KeyDown(object sender, KeyEventArgs e)
        {
            switch (e.KeyCode)
            {
                case Keys.Escape:
                    Application.Exit();
                    break;
                case Keys.PageDown:
                    LoadImage(++ImageNumNow);
                    break;
                case Keys.PageUp:
                    LoadImage(--ImageNumNow);
                    break;
                case Keys.Home:
                    LoadImage(ImageNumNow = 0);
                    break;
                case Keys.End:
                    LoadImage(ImageNumNow = _files.Length - 1);
                    break;
                case Keys.Add:
                case Keys.Oemplus:
                    _ratioZoom *= _perZoom;
                    LoadImage(ImageNumNow);
                    break;
                case Keys.Subtract:
                case Keys.OemMinus:
                    _ratioZoom *= 1.0 / _perZoom;
                    LoadImage(ImageNumNow);
                    break;
                case Keys.W:
                    FitWidth_Click(null, null);
                    break;
                case Keys.H:
                    FitHeight_Click(null, null);
                    break;
                case Keys.NumPad0:
                    _ratioZoom = 1.0;
                    LoadImage(ImageNumNow);
                    break;
                case Keys.Up:
                    ImageUp(_distanceY);
                    break;
                case Keys.Down:
                    ImageDown(_distanceY);
                    break;
                case Keys.Left:
                    ImageLeft(_distanceX);
                    break;
                case Keys.Right:
                    ImageRight(_distanceX);
                    break;
                case Keys.NumPad8: // Move to top.
                    ImageUp(pic_Main.Height);
                    ImageXMiddle();
                    break;
                case Keys.NumPad2: // Move to bottom.
                    ImageDown(pic_Main.Height);
                    ImageXMiddle();
                    break;
                case Keys.NumPad4: // Move to Left.
                    ImageLeft(pic_Main.Width);
                    ImageYMiddle();
                    break;
                case Keys.NumPad6: // Move to Right.
                    ImageRight(pic_Main.Width);
                    ImageYMiddle();
                    break;
                case Keys.NumPad7: // Move to top and left.
                    ImageUp(pic_Main.Height);
                    ImageLeft(pic_Main.Width);
                    break;
                case Keys.NumPad9: // Move to top and right.
                    ImageUp(pic_Main.Height);
                    ImageRight(pic_Main.Width);
                    break;
                case Keys.NumPad1: // Move to bottom and left.
                    ImageDown(pic_Main.Height);
                    ImageLeft(pic_Main.Width);
                    break;
                case Keys.NumPad3: // Move to bottom and right.
                    ImageDown(pic_Main.Height);
                    ImageRight(pic_Main.Width);
                    break;
                case Keys.NumPad5: // Move to middle.
                    ImageXMiddle();
                    ImageYMiddle();
                    break;
                //
                // Video Player
                //
                case Keys.Z:
                    Reverse_Click(null, null);
                    break;
                case Keys.X:
                    Pause_Click(null, null);
                    break;
                case Keys.C:
                    Play_Click(null, null);
                    break;
                case Keys.V:
                    Rewind_Click(null, null);
                    break;
                case Keys.S:
                    Stop_Click(null, null);
                    break;
                case Keys.Space:
                    if (PlayerStatus == PlayMode.Pause)
                    {
                        PlayerStatus = _prePlayerStatus;
                        _prePlayerStatus = PlayMode.Pause;
                    }
                    else
                    {
                        _prePlayerStatus = PlayerStatus;
                        PlayerStatus = PlayMode.Pause;
                    }
                    break;
            }
        }

        private void Form1_SizeChanged(object sender, EventArgs e)
        {
            panel_Image.Location = new Point(0, toolStrip1.Bottom);
            panel_Image.Size = new Size(this.ClientSize.Width, toolStrip_PlayCtrlBar.Top - panel_Image.Top);
            SetDistance();
            SetBarLocSize();
            LoadImage(ImageNumNow);
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            timer_Cache.Stop();
            _timerPlay.Stop();
            _timerReverse.Stop();

            SaveSetting();
        }

        private void lbl_Status_TextChanged(object sender, EventArgs e)
        {
            if (!String.IsNullOrWhiteSpace(lbl_Status.Text))
            {
                lbl_Status.Visible = true;

                if (statusTimer != null)
                {
                    statusTimer.CancelAsync();
                    statusTimer.Dispose();
                }

                statusTimer = new BackgroundWorker();
                statusTimer.WorkerSupportsCancellation = true;
                statusTimer.WorkerReportsProgress = true;
                statusTimer.DoWork += new DoWorkEventHandler(
                    (object doWorkSender, DoWorkEventArgs doWorkArgs) =>
                    {
                        Thread.Sleep(500);
                        if ((doWorkSender as BackgroundWorker).CancellationPending)
                        {
                            doWorkArgs.Cancel = true;
                            return;
                        }
                        (doWorkSender as BackgroundWorker).ReportProgress(100);
                    });
                statusTimer.ProgressChanged += new ProgressChangedEventHandler(
                    (object progressSender, ProgressChangedEventArgs progressArgv) =>
                    {
                        lbl_Status.Visible = false;
                        lbl_Status.Text = "";
                    });

                statusTimer.RunWorkerAsync();
            }
        }

        private void timer_Cache_Tick(object sender, EventArgs e)
        {
            int cacheBackward = uiSetting.CacheBackward;
            int cacheForward =uiSetting.CacheForward;
            int[] cachePool = new int[uiSetting.CachePoolLength];
            int caching = 0;

            // throw rotten apple, oh, I mean retire old cache.
            while (caching < _imageCache.Keys.Count)
            {
                int key = _imageCache.Keys.ToArray()[caching];

                if ((uiSetting.FirstChecked ? key != 0 : true) && // If cache first image, do not dispose key = 0.
                    ((uiSetting.LastChecked ? key != _files.Length : true) && // If cache last image, do not dispose key = last image.
                    (key < ImageNumNow - cacheBackward ||
                    key > ImageNumNow + cacheForward) &&
                    (key < _AnywhereDoor - cacheBackward ||
                    key > _AnywhereDoor + cacheForward))) // Do not dispose image in range.
                {
                    Image disposeImage = _imageCache[key];
                    _imageCache.Remove(key);
                    disposeImage.Dispose();

                }
                else
                {
                    caching++;
                }
            }

            caching = 0;

            // Create caching list.
            for (int i = 0; i < cachePool.Length; i++)
            {
                cachePool[i] = -1;
            }
            for (int i = 1; i <= cacheForward; i++)
            {
                cachePool[caching++] = ImageNumNow + i;
                cachePool[caching++] = _AnywhereDoor + i;
            }
            for (int i = 1; i <= cacheBackward; i++)
            {
                cachePool[caching++] = ImageNumNow - i;
                cachePool[caching++] = _AnywhereDoor - i;
            }
            if (uiSetting.FirstChecked)
            {
                cachePool[caching++] = 0;
            }
            if (uiSetting.LastChecked)
            {
                cachePool[caching++] = _files.Length;
            }

            // Cache.
            for (caching = 0; caching < cachePool.Length; caching++)
            {
                if (_imageCache.ContainsKey(cachePool[caching])) // Skip exist cache.
                {
                    caching++;
                }
                else
                {
                    if (cachePool[caching] >= 0 && cachePool[caching] < _files.Length)
                    {
                        try
                        {
                            _imageCache.Add(
                                cachePool[caching],
                                ImageFromFile(_files[cachePool[caching]]));
                        }
                        catch (OutOfMemoryException ex)
                        {
                            long memory = System.Diagnostics.Process.GetCurrentProcess().PrivateMemorySize64;
                            this.Text += Txt("cacheFull", "(Cache Full)");
                            System.IO.File.AppendAllText("error.log", String.Format("-----\n{0}\n{1}\n-----\n", ex.Message, memory));
                            _imageCache.Remove(cachePool[caching]);
                            timer_Cache.Interval += 100;
                        }
                    }
                    break;
                }
            }
        }

        private void _timerReverse_Tick(object sender, EventArgs e)
        {
            LoadImage(--ImageNumNow);
        }

        private void _timerPlay_Tick(object sender, EventArgs e)
        {
            LoadImage(++ImageNumNow);
        }

        //
        // Tool Bar
        //
        private void selectFile_Click(object sender, EventArgs e)
        {
            OpenFileDialog dialog = new OpenFileDialog();

            dialog.Title = Txt("dialog_SelectFile", "Select File");
            dialog.Multiselect = false;
            dialog.InitialDirectory = _currentPath;
            this.Deactivate -= Form1_Deactivate;
            if (dialog.ShowDialog() == DialogResult.OK)
            {
                LoadFile(dialog.FileName);
            }
            this.Deactivate += Form1_Deactivate;
        }

        private void FitWidth_Click(object sender, EventArgs e)
        {
            _ratioZoom = 1.0;
            if (_sizeMode != SizeMode.FitWidth)
            {
                _sizeMode = SizeMode.FitWidth;
            }
            LoadImage(ImageNumNow);
        }

        private void FitHeight_Click(object sender, EventArgs e)
        {
            _ratioZoom = 1.0;
            if (_sizeMode != SizeMode.FitHeigth)
            {
                _sizeMode = SizeMode.FitHeigth;
            }
            LoadImage(ImageNumNow);
        }

        private void Original_Click(object sender, EventArgs e)
        {
            _ratioZoom = 1.0;
            if (_sizeMode != SizeMode.Original)
            {
                _sizeMode = SizeMode.Original;
            }
            LoadImage(ImageNumNow);
        }

        /// <summary>
        /// Load previous image in right picture box.
        /// </summary>
        private void DoublePageRight_Click(object sender, EventArgs e)
        {
            if (pic_Sub.Visible)
            {
                uiSetting.CacheMinimum = 0;
                pic_Sub.Image = null;
                pic_Sub.Visible = false;
                LoadImage(ImageNumNow);
            }
            else
            {
                _rightFlip = true;
                uiSetting.CacheMinimum = 1;
                pic_Sub.Visible = true;
                LoadImage(ImageNumNow);
            }
        }

        /// <summary>
        /// Load next image in right picture box.
        /// </summary>
        private void DoublePageLeft_Click(object sender, EventArgs e)
        {
            if (pic_Sub.Visible)
            {
                uiSetting.CacheMinimum = 0;
                pic_Sub.Image = null;
                pic_Sub.Visible = false;
                LoadImage(ImageNumNow);
            }
            else
            {
                _rightFlip = false;
                uiSetting.CacheMinimum = 1;
                pic_Sub.Visible = true;
                LoadImage(ImageNumNow);
            }
        }

        private void FullScreen_Click(object sender, EventArgs e)
        {
            FullScreen();
        }

        private void property_Click(object sender, EventArgs e)
        {
            if (uiSetting.Visible)
            {
                btn_OK_Click(sender, e);
            }
            else
            {
                uiSetting.FontInformation =
                    Txt("fontName", "Font Name: ") + this.Font.FontFamily.Name +
                    "\n" + Txt("fontSize", "Font Size: ") + this.Font.Size.ToString();

                uiSetting.Visible = true;
                uiSetting.Enabled = true;
            }
        }

        private void btn_Info_Click(object sender, EventArgs e)
        {
            Form form_Info = new Form();
            RichTextBox txtBx_Info = new RichTextBox();

            form_Info.Size = new Size(640, 480);
            form_Info.Text = Txt("dialog_Info", "Information");
            form_Info.Icon = this.Icon;
            form_Info.Controls.Add(txtBx_Info);
            txtBx_Info.Dock = DockStyle.Fill;
            txtBx_Info.Font = this.Font;
            txtBx_Info.ReadOnly = true;
            txtBx_Info.AppendText(Txt("AppName", "TripleC ComiX Viewer"));
            txtBx_Info.SelectionAlignment = HorizontalAlignment.Center;
            txtBx_Info.AppendText("\n" + Txt("AppDescript", "A simply image viewer suit for reading comic."));
            txtBx_Info.AppendText("\n\n" + Txt("AppVer", "Version: "));
            txtBx_Info.AppendText("\n" + Txt("AppAuthor", "\nAuthor: TripleC feat. benimut") + "\n");
            txtBx_Info.SelectionAlignment = HorizontalAlignment.Left;
            txtBx_Info.AppendText("\n" + Txt("AppUsage", "Usage: "));
            txtBx_Info.SelectionStart = 0;

            form_Info.FormClosed += new FormClosedEventHandler((object closedSender, FormClosedEventArgs closedArgs) =>
            {
                this.Deactivate += Form1_Deactivate;
            });

            this.Deactivate -= Form1_Deactivate;
            form_Info.Show();
        }

        //
        // Menu
        //
        private void selectFolderToolStripMenuItem_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog dialog = new FolderBrowserDialog();

            dialog.Description = Txt("dialog_SelectFolder", "Select folder");
            dialog.SelectedPath = _currentPath;

            this.Deactivate -= Form1_Deactivate;
            if (dialog.ShowDialog() == DialogResult.OK)
            {
                LoadFolder(dialog.SelectedPath);
            }
            this.Deactivate += Form1_Deactivate;
        }

        private void previousFolderToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (!String.IsNullOrWhiteSpace(_currentPath))
            {
                try
                {
                    if (Directory.GetParent(_currentPath) != null)
                    {
                        DirectoryInfo[] siblings = Directory.GetParent(_currentPath).GetDirectories();

                        for (int n = 1; n < siblings.Length; n++)
                        {
                            if (siblings[n].FullName == _currentPath)
                            {
                                LoadFolder(siblings[--n].FullName);
                                break;
                            }
                        }
                    }
                }
                catch(UnauthorizedAccessException)
                {
                    lbl_Status.Text = "UnauthorizedAccess: \"" + _currentPath + "\"";
                    previousFolderToolStripMenuItem_Click(sender, e);
                }
            }
        }

        private void nextFolderToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (!String.IsNullOrWhiteSpace(_currentPath))
            {
                try
                {
                    if (Directory.GetParent(_currentPath) != null)
                    {
                        DirectoryInfo[] siblings = Directory.GetParent(_currentPath).GetDirectories();

                        for (int n = 0; n < siblings.Length - 1; n++)
                        {
                            if (siblings[n].FullName == _currentPath)
                            {
                                LoadFolder(siblings[++n].FullName);
                                break;
                            }
                        }
                    }
                }
                catch (UnauthorizedAccessException)
                {
                    lbl_Status.Text = "UnauthorizedAccess: \"" + _currentPath + "\"";
                    nextFolderToolStripMenuItem_Click(sender, e);
                }
            }
        }

        private void parentFolderToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (!String.IsNullOrWhiteSpace(_currentPath))
            {
                try
                {
                    if(Directory.GetParent(_currentPath) != null)
                    {
                        LoadFolder(Directory.GetParent(_currentPath).FullName);
                    }
                }
                catch (UnauthorizedAccessException)
                {
                    lbl_Status.Text = "UnauthorizedAccess: \"" + _currentPath + "\"";
                    previousFolderToolStripMenuItem_Click(sender, e);
                }
            }
        }

        private void jumpToChildFolderToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (!String.IsNullOrWhiteSpace(_currentPath))
            {
                try
                {
                    string[] siblings = Directory.GetDirectories(_currentPath);

                    if(siblings.Length > 0)
                    {
                        LoadFolder(siblings[0]);
                    }
                }
                catch (UnauthorizedAccessException)
                {
                    lbl_Status.Text = "UnauthorizedAccess: \"" + _currentPath + "\"";
                    previousFolderToolStripMenuItem_Click(sender, e);
                }
            }
        }

        private void registryToolStripMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                using (RegistryKey shell = Registry.ClassesRoot.OpenSubKey(@"*\shell", true))
                {
                    using (RegistryKey custom = shell.CreateSubKey(Txt("AppName", "TripleC ComiX Viewer")))
                    {
                        using (RegistryKey cmd = custom.CreateSubKey("command"))
                        {
                            cmd.SetValue(string.Empty, string.Format("{0} \"%1\"", Application.ExecutablePath));
                        }
                    }
                }
                this.Deactivate -= Form1_Deactivate;
                if (MessageBox.Show("Success!", "Success!", MessageBoxButtons.OK) == DialogResult.OK)
                {
                    this.Deactivate += Form1_Deactivate;
                }
            }
            catch (Exception ex)
            {
                this.Deactivate -= Form1_Deactivate;
                if (MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK) != System.Windows.Forms.DialogResult.Cancel)
                {
                    this.Deactivate += Form1_Deactivate;
                }
            }
        }

        private void unregistryToolStripMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                using (RegistryKey shell = Registry.ClassesRoot.OpenSubKey(@"*\shell", true))
                {
                    shell.DeleteSubKeyTree(Txt("AppName", "TripleC ComiX Viewer"));
                }
                this.Deactivate -= Form1_Deactivate;
                if (MessageBox.Show("Success!", "Success!", MessageBoxButtons.OK) == DialogResult.OK)
                {
                    this.Deactivate += Form1_Deactivate;
                }
            }
            catch (Exception ex)
            {
                this.Deactivate -= Form1_Deactivate;
                if (MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK) != System.Windows.Forms.DialogResult.Cancel)
                {
                    this.Deactivate += Form1_Deactivate;
                }
            }
        }

        private void importPanoramaToolStripMenuItem_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog dialog = new FolderBrowserDialog();

            dialog.Description = Txt("dialog_SelectPanorama", "Select Panorama folder");
            dialog.SelectedPath = _currentPath;

            this.Deactivate -= Form1_Deactivate;
            if (dialog.ShowDialog() == DialogResult.OK)
            {
                string[] files;
                string setting;

                files = SortFileName(GetFiles(dialog.SelectedPath));
                setting = Path.GetDirectoryName(files[0]) + @"\Setting.ini";

                if (File.Exists(setting))
                {
                    IEnumerable points = File.ReadLines(setting);
                    DataTable table = new DataTable();
                    int phaseCount = 0;

                    table.Columns.AddRange(new DataColumn[]{
                        new DataColumn("ID", typeof(int)),
                        new DataColumn("X", typeof(int)),
                        new DataColumn("Y", typeof(int)),
                        new DataColumn("Time", typeof(double)),
                        new DataColumn("Tip", typeof(string))
                    });

                    foreach (string line in points)
                    {
                        string[] lines = line.Split(',');
                        if (lines.Length >= 5)
                        {
                            if (lines.Length > 5)
                            {
                                for (int p = 5; p < lines.Length; p++)
                                {
                                    lines[4] = String.Concat(lines[4], ",", lines[p]);
                                }
                            }
                            table.Rows.Add(
                                Convert.ToInt32(lines[0]),
                                Convert.ToInt32(lines[1]),
                                Convert.ToInt32(lines[2]),
                                Convert.ToDouble(lines[3]),
                                lines[4]);
                        }
                    }

                    if (table.Rows.Count > 0)
                    {
                        phaseCount = Convert.ToInt32(table.Compute("max(ID)", "")) + 1;
                        _pointVSTime = new Dictionary<Point, int>[phaseCount];
                        for (int key = 0; key < phaseCount; key++)
                        {
                            _pointVSTime[key] = new Dictionary<Point, int>();
                        }
                        foreach (DataRow row in table.Rows)
                        {
                            int id = Convert.ToInt32(row["ID"]);
                            int x = Convert.ToInt32(row["X"]);
                            int y = Convert.ToInt32(row["Y"]);
                            double t = Convert.ToDouble(row["Time"]);
                            string tip = row["Tip"].ToString();
                        }
                    }
                }
            }
            this.Deactivate += Form1_Deactivate;
        }

        private void setAnywhereDoorToolStripMenuItem_Click(object sender, EventArgs e)
        {
            _AnywhereDoor = _imageNumNow;
        }

        private void jumpToAnywhereDoorToolStripMenuItem_Click(object sender, EventArgs e)
        {
            int from = ImageNumNow;
            LoadImage(ImageNumNow = _AnywhereDoor);
            _AnywhereDoor = from;
        }

        private void showSiblingFoldersToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (!String.IsNullOrWhiteSpace(_currentPath))
            {
                if(Directory.GetParent(_currentPath) != null)
                {
                Form form_List = new Form();
                DataGridView view_List = new DataGridView();
                DirectoryInfo[] siblings = Directory.GetParent(_currentPath).GetDirectories();
                int currentDirNum = 0;

                for (int n = 1; n < siblings.Length; n++)
                {
                    if (siblings[n].FullName == _currentPath)
                    {
                        currentDirNum = n;
                        break;
                    }
                }

                form_List.Size = new Size(640, 480);
                form_List.Text = Txt("dialog_List", "File List");
                form_List.Controls.Add(view_List);
                form_List.Icon = this.Icon;
                form_List.TopMost = true;
                view_List.ScrollBars = ScrollBars.Both;
                view_List.Columns.Add("Path", "Path");
                view_List.Dock = DockStyle.Fill;
                view_List.Columns["Path"].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
                view_List.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
                view_List.AllowUserToAddRows = false;
                view_List.AllowUserToDeleteRows = false;
                view_List.ReadOnly = true;
                foreach (DirectoryInfo dir in siblings)
                {
                    view_List.Rows.Add(dir.FullName);
                }
                view_List.SelectionChanged += new EventHandler((object eventSender, EventArgs eventArgs) =>
                {
                    if (view_List != null)
                    {
                        if (view_List.Rows.Count > currentDirNum &&
                            view_List.CurrentRow.Index != currentDirNum)
                        {
                            view_List.Rows[currentDirNum].Selected = true;
                            view_List.CurrentRow.Selected = false;
                        }
                    }
                });
                form_List.FormClosed += new FormClosedEventHandler((object closedSender, FormClosedEventArgs closedArgs) =>
                {
                    this.Deactivate += Form1_Deactivate;
                });

                this.Deactivate -= Form1_Deactivate;
                form_List.Show();
                }
            }
        }

        private void showFileListToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //ShowFileList();
            Browser browser = new Browser(this);
            browser.Font = this.Font;
            browser.FormClosed += new FormClosedEventHandler((object closedSender, FormClosedEventArgs closedArgs) =>
            {
                this.Deactivate += Form1_Deactivate;
                this.Show();
            });
            this.Deactivate -= Form1_Deactivate;
            this.Hide();
            browser.Show();
        }

        //
        // Play Control Bar
        //
        private void toolStrip_PlayCtrlBar_MouseLeave(object sender, EventArgs e)
        {
            if (this.WindowState == FormWindowState.Maximized)
            {
                toolStrip_PlayCtrlBar.Visible = false;
            }
        }

        private void toolStrip_PlayCtrlBar_VisibleChanged(object sender, EventArgs e)
        {
            panel_Image.Size = new Size(
                this.ClientSize.Width,
                (toolStrip_PlayCtrlBar.Visible) ? toolStrip_PlayCtrlBar.Top - panel_Image.Top :
                this.ClientSize.Height - panel_Image.Top);
            SetDistance();
            if (_sizeMode == SizeMode.FitHeigth)
            {
                LoadImage(ImageNumNow);
            }
            else
            {
                _imageTop = panel_Image.ClientSize.Height - pic_Main.Height;
                _imageLeft = panel_Image.ClientSize.Width - pic_Main.Width;
                if (toolStrip_PlayCtrlBar.Visible)
                {
                    ImageDown(toolStrip_PlayCtrlBar.Height);
                }
                else
                {
                    ImageUp(toolStrip_PlayCtrlBar.Height);
                }
            }
        }

        private void PreFrame_Click(object sender, EventArgs e)
        {
            LoadImage(--ImageNumNow);
        }

        private void Reverse_Click(object sender, EventArgs e)
        {
            PlayerStatus = PlayMode.Reverse;
        }

        private void Pause_Click(object sender, EventArgs e)
        {
            PlayerStatus = PlayMode.Pause;
        }

        private void Play_Click(object sender, EventArgs e)
        {
            PlayerStatus = PlayMode.Play;
        }

        private void Rewind_Click(object sender, EventArgs e)
        {
            _rewindRatio *= uiSetting.RewindRatio;
            PlayerStatus = PlayMode.Rewind;
        }

        private void NextFrame_Click(object sender, EventArgs e)
        {
            LoadImage(++ImageNumNow);
        }

        private void Stop_Click(object sender, EventArgs e)
        {
            PlayerStatus = PlayMode.Pause;
            LoadImage(ImageNumNow = 0);
        }

        //
        // Property Setting
        //
        private void num_RatioX_ValueChanged(object sender, EventArgs e)
        {
            _ratioX = uiSetting.RatioX;
            _distanceX = Convert.ToInt32(panel_Image.ClientSize.Width * _ratioX);
        }

        private void num_RatioY_ValueChanged(object sender, EventArgs e)
        {
            _ratioY = uiSetting.RatioY;
            _distanceY = Convert.ToInt32(panel_Image.ClientSize.Width * _ratioY);
        }

        private void num_RatioZoom_ValueChanged(object sender, EventArgs e)
        {
            _perZoom = uiSetting.RatioZoom;
        }

        private void check_Bar_CheckedChanged(object sender, EventArgs e)
        {
            SetBarLocSize();
            pic_BarFront.Visible = uiSetting.BarChecked;
            pic_BarBack.Visible = uiSetting.BarChecked;
            toolStrip_PlayCtrlBar.Visible = uiSetting.BarChecked;
        }

        private void btn_Font_Click(object sender, EventArgs e)
        {
            FontDialog dialog = new FontDialog();
            if (dialog.ShowDialog() == DialogResult.OK)
            {
                SetFont(dialog.Font);
            }
        }

        private void btn_OK_Click(object sender, EventArgs e)
        {
            uiSetting.Enabled = false;
            uiSetting.Visible = false;
        }

        //
        // Image
        //
        private void Image_MouseMove(object sender, MouseEventArgs e)
        {
            Point screenLocMouse = (sender as Control).PointToScreen(e.Location);

            if (this.WindowState == FormWindowState.Maximized)
            {
                CursorHide = true;
            }

            if(_imageDrag)
            {
                ImageDrag(
                    screenLocMouse.X - _imageMouse.X,
                    screenLocMouse.Y - _imageMouse.Y);
                _imageMouse = screenLocMouse;
            }

            if (uiSetting.BarChecked)
            {
                AutoShowBar(
                    screenLocMouse,
                    panel_Image.RectangleToScreen(new Rectangle(
                        new Point(20, panel_Image.Height - 90),
                        pic_BarBack.Size)));
            }
        }

        private void Image_MouseLeave(object sender, EventArgs e)
        {
            _imageDrag = false;
            CursorHide = false;
        }
        
        private void Image_MouseDown(object sender, MouseEventArgs e)
        {
            _imageDrag = true;
            _imageMouse = (sender as Control).PointToScreen(e.Location);
        }

        private void Image_MouseUp(object sender, MouseEventArgs e)
        {
            _imageDrag = false;
        }

        //
        // Picture Box Time Line
        //
        private void pic_Bar_MouseDown(object sender, MouseEventArgs e)
        {
            _scrolling = true;

            pic_BarFront.Width = (e.X >= 0) ? e.X : 0;
        }

        private void pic_Bar_MouseUp(object sender, MouseEventArgs e)
        {
            _scrolling = false;
        }

        private void pic_Bar_MouseLeave(object sender, EventArgs e)
        {
            _scrolling = false;
            pic_BarBack.Visible = false;
            pic_BarFront.Visible = false;
            pic_BarFront.Refresh();
            pic_BarBack.Refresh();
        }

        private void pic_Bar_MouseMove(object sender, MouseEventArgs e)
        {
            int scale = e.X;

            _mouseP = e.Location;

            if (_scrolling)
            {
                int imageNumNew = e.X * _files.Length / pic_BarBack.Width;

                if (imageNumNew < 0)
                {
                    imageNumNew = 0;
                }
                else if (imageNumNew >= _files.Length)
                {
                    imageNumNew = _files.Length - 1;
                }

                if (imageNumNew != _imageNumNow)
                {
                    LoadImage(_imageNumNow = imageNumNew);
                }
            }
        }
    }
}
